//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

// dllentry.c
//
// This file is provide the entry point
// -- _DllMainCRTStartup() for elastos.dll.
//

#include <elatypes.h>
#include <eladef.h>

#if !(defined(_win32)||defined(_wince))

#include <csdetect.h>
#include <usyscall.h>

#if defined(MEMORYSPY)
#include "memspy.h"
extern CriticalSection g_sectMemSpy;
extern Void MSpySetArgs(wchar_t uArgId, UInt32 uStopIndex, Address addr);
#endif

extern void ThreadEntry(
            ECode (*pEntry)(void*),
            void *pArg);

/*
 * breakin a running process.
 * 1) create a new thread for the debuggee process, as DebugBreakThread().
 * 2) the new thread has a DebugBreak(). so it will be hit soon.
 * 3) DebugBreak() hit, process stopped, breakin succeeded.
 * after that, we can set new breakpoints at where we want.
 */
ECode DebugBreakThread(PVoid pvParam)
{
//TODO: need to check whether debuggee is debug-compiled??
    DebugBreak();
    return NOERROR;
}

#endif //#if !defined(_win32)

typedef void (__cdecl *PF)(void);
#if defined(_GNUC)
void initterm(PF *pfbegin);
EXTERN_C PF __CTOR_LIST__[];
EXTERN_C PF __DTOR_LIST__[];
#elif defined(_EVC) || defined(_MSVC)
EXTERN_C void __cdecl initterm(PF *pfbegin, PF *pfend);
EXTERN_C PF __xc_a[];
EXTERN_C PF __xc_z[];
EXTERN_C PF __xt_a[];
EXTERN_C PF __xt_z[];
#endif

extern void InitTaskMemory();
extern void UninitTaskMemory();

EXTERN_C _ELASTOS Boolean __stdcall DllMain(
                PVoid hDllHandle, UInt32 dwReason, PVoid preserved);

EXTERN_C _ELASTOS Boolean __stdcall _DllMainCRTStartup(
    PVoid hDllHandle,
    UInt32 dwReason,
    PVoid preserved)
{
    int ret;

    if (dwReason == DLL_PROCESS_ATTACH) {

#if !(defined(_win32) || defined(_wince))

        CSDETECT_INIT   //It must be the first

#ifdef MULTI_RESOURCE_DEADLOCK_DETECT
        MULTI_RESOURCE_DEADLOCK_INIT //for deadlock check about cs and mutex
#endif 

        InitTaskMemory();

        //save thread entry for dbgstub.
        UInt32 buf[] = {(UInt32)ThreadEntry, (UInt32)DebugBreakThread};
        SysSendToKernel(buf, 1);

#if defined(MEMORYSPY)
        ECode ec = _CCriticalSection_Initialize(&g_sectMemSpy);
        if (ec != NOERROR) {
            DebugBreak();
            return 0;
        }

        wchar_t wchArgId;
        Int32 stopIndex = 0;
        Address addr = 0;

        SysGetMemtraceArgs(&wchArgId, &stopIndex, &addr);

        MSpySetArgs(wchArgId, stopIndex, addr);

        MemSpyInitMemSpyArch();
#endif //#if defined(MEMORYSPY)

#endif //#if !defined(_win32)

#if defined(_GNUC)
        initterm(__CTOR_LIST__);
#elif defined(_EVC) || defined(_MSVC)
        initterm(__xc_a, __xc_z);
#else
#error unknown compiler
#endif
    }

    ret = DllMain(hDllHandle, dwReason, preserved);

    if (dwReason == DLL_PROCESS_DETACH) {
#if defined(_GNUC)
        initterm(__DTOR_LIST__);
#elif defined(_EVC) || defined(_MSVC)
        initterm(__xt_a, __xt_z);
#else
#error unknown compiler
#endif

#if !(defined(_win32)||defined(_wince))

#if defined(MEMORYSPY)
        MemSpyExitAndReportMemSpyInfo();

        _CCriticalSection_Terminate(&g_sectMemSpy);
#endif //#if defined(MEMORYSPY)

        UninitTaskMemory();

#endif //#if !defined(_win32)
    }

    return ret;
}

#if defined(_GNUC)
void initterm(PF *pfbegin)
{
    // constructor and destructor should begin with 0xfffffff
    // and end of 0

    if (*pfbegin == (PF)-1)
        pfbegin ++;
    else {
        DebugBreak();
    }

    while (*pfbegin) {
        (**pfbegin)();
        pfbegin ++;
    }
}
#elif defined(_EVC) || defined(_MSVC)
EXTERN_C void __cdecl initterm(PF *pfbegin, PF *pfend)
{
    while (pfbegin < pfend) {
        if (*pfbegin != NULL) {
            (**pfbegin)();
        }
        pfbegin++;
    }
}
#endif
